﻿using Microsoft.EntityFrameworkCore.Metadata.Builders;
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using Volo.Abp;
using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities;
using Volo.Abp.EntityFrameworkCore.Modeling;
using Volo.Abp.MultiTenancy;

namespace Xms.Abp.Storage;

public static class XmsEntityTypeBuilderExtensions
{
    public static void ConfigureByConventionWithIndex(this EntityTypeBuilder b)
    {
        b.ConfigureByConvention();
        b.TryConfigureKey();
        b.TryConfigureMultiTenantIndex();
        b.TryConfigureCreationIndex();
        b.TryConfigureIsDeletedIndex();
    }

    public static void TryConfigureKey(this EntityTypeBuilder b)
    {
        if (b.Metadata.ClrType.IsSubclassOf(typeof(Entity<>)))
        {
            b.HasKey(nameof(Entity<string>.Id));
        }
        else
        {
            var keys = b.Metadata.ClrType.GetProperties().Where(r => r.GetCustomAttribute<KeyAttribute>() != null).Select(r => r.Name).ToArray();
            if (keys != null && keys.Any())
            {
                b.HasKey(keys);
            }
        }
    }

    public static void TryConfigureMultiTenantIndex(this EntityTypeBuilder b)
    {
        if (b.Metadata.ClrType.IsAssignableTo<IMultiTenant>())
        {
            b.HasIndex(nameof(IMultiTenant.TenantId));
        }
    }

    public static void TryConfigureCreationIndex(this EntityTypeBuilder b)
    {
        if (b.Metadata.ClrType.IsAssignableTo<IHasCreationTime>())
        {
            b.HasIndex(nameof(IHasCreationTime.CreationTime));
        }
        if (b.Metadata.ClrType.IsAssignableTo<IMayHaveCreator>())
        {
            b.HasIndex(nameof(IMayHaveCreator.CreatorId));
        }
        else if (b.Metadata.ClrType.IsAssignableTo<IMustHaveCreator>())
        {
            b.HasIndex(nameof(IMustHaveCreator.CreatorId));
        }
    }

    public static void TryConfigureIsDeletedIndex(this EntityTypeBuilder b)
    {
        if (b.Metadata.ClrType.IsAssignableTo<ISoftDelete>())
        {
            b.HasIndex(nameof(ISoftDelete.IsDeleted));
        }
    }
}
